#include "videoplayer.h"
#include <QtDebug>

int VideoPlayer::initSDL(){
    SDL_AudioSpec want;
    //采样率
    //方案一：修改重采样率为原来的倍数，这样可以做到倍速播放，但是有缺点，只能在打开的时候设置一下，后续无法更改
    //want.freq = m_aSwrOutSpec.nSampleRate * m_speedPlayRate;
    want.freq = m_aSwrOutSpec.nSampleRate;
    //采样格式
    want.format = AUDIO_S16LSB;
    //声道数
    want.channels = m_aSwrOutSpec.nCh;
    //音频缓冲区的样本数
    want.samples = 1024;
    //回调
    want.callback = sdlAudioCallbackFunc;
    //传递给回调的参数
    want.userdata = this;

    if(SDL_OpenAudio(&want,nullptr)){
       qDebug() << "SDL_OpenAudio error" << SDL_GetError();
       return -1;
    }
    return 0;
}

int VideoPlayer::initAudioInfo(){
    int ret = initDecoder(&m_aDecodeCtx,&m_aStream,AVMEDIA_TYPE_AUDIO);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initDecoder error" << errbuf;
        return ret;
    }

    // 初始化音频重采样
    ret = initSwr();
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initSwr error" << errbuf;
        return ret;
    }

    // 初始化SDL
    ret = initSDL();
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initSDL error" << errbuf;
        return ret;
    }

    return 0;
}

void VideoPlayer::freeAudio(){
    m_aSwrOutIdx = 0;
    m_aSwrOutSize = 0;
    m_aTime = 0;
    m_aCanFree = false;
    m_aSeekTime = -1;
    clearAudioPktList();
    avcodec_free_context(&m_aDecodeCtx);
    swr_free(&m_aSwrCtx);
    av_frame_free(&m_aSwrInFrame);
    if(m_aSwrOutFrame){
        av_freep(&m_aSwrOutFrame->data[0]);// 因手动创建了data[0]的空间
        av_frame_free(&m_aSwrOutFrame);
    }

    // 停止播放
    SDL_PauseAudio(1);
    SDL_CloseAudio();
}

void VideoPlayer::addAudioPkt(AVPacket &pkt){
    m_aMutex.lock();
    m_aPktList.push_back(pkt);
    m_aMutex.signal();
    m_aMutex.unlock();
}

void VideoPlayer::clearAudioPktList(){
    m_aMutex.lock();
    for(AVPacket &pkt : m_aPktList){
        av_packet_unref(&pkt);
    }
    m_aPktList.clear();
    m_aMutex.unlock();
}

void VideoPlayer::sdlAudioCallbackFunc(void *userdata, Uint8 *stream, int len){
    VideoPlayer *player = (VideoPlayer *)userdata;
    player->sdlAudioCallback(stream,len);
}

void VideoPlayer::sdlAudioCallback(Uint8 *stream, int len){
    //清零(静音)
    SDL_memset(stream,0,len);
    //len:SDL音频缓冲区剩余的大小(还未填充的大小)
    while(len > 0){
        if(m_TaskState == Paused) break;
        if(m_TaskState == Stopped){
            m_aCanFree = true;
            break;
        }

        //说明当前的PCM的数据已全部拷贝到SDL的音频缓冲区
        if(m_aSwrOutIdx >= m_aSwrOutSize){
            //全新PCM的大小
            m_aSwrOutSize = decodeAudio();
            //索引清0
            m_aSwrOutIdx = 0;
            //没有解码出PCM数据,就静音处理
            if(m_aSwrOutSize <= 0){
                //假定PCM的大小
                m_aSwrOutSize = 1024;
                //给PCM填充0(静音)
                memset(m_aSwrOutFrame->data[0],0,m_aSwrOutSize);
            }
        }
        //本次需要填充到stream中的PCM数据大小
        int fillLen = m_aSwrOutSize - m_aSwrOutIdx;
        fillLen = std::min(fillLen,len);

        //获取当前音量
        int volume = m_mute? 0 :((m_volume * 1.0/100.0) * SDL_MIX_MAXVOLUME);
       //填充SDL缓冲区
        SDL_MixAudio(stream,m_aSwrOutFrame->data[0] + m_aSwrOutIdx,fillLen,volume);
        //移动偏移量
        len -= fillLen;
        stream += fillLen;
        m_aSwrOutIdx += fillLen;
    }
}

int VideoPlayer::decodeAudio(){
    //加锁
    m_aMutex.lock();

    if(m_aPktList.empty() || m_TaskState == Stopped){
        m_aMutex.unlock();
        return 0;
    }

    //取出头部的数据
    AVPacket pkt = m_aPktList.front();
    //从头部中删除
    m_aPktList.pop_front();
    //解锁
    m_aMutex.unlock();
    //保存音频时钟
    if(pkt.pts != AV_NOPTS_VALUE){
        m_aTime = av_q2d(m_aStream->time_base) * pkt.pts;
        //通知外界：播放时间点发生了改变
        emit timeChanged(this);
    }

    //如果是视频，不能在这个位置判断(不能提前释放pkt,不然会导致B帧,P帧解码失效,画面撕裂)
    //如果音频的时间早于seekTime,直接丢弃
    if(m_aSeekTime >= 0){
        if(m_aTime < m_aSeekTime){
            av_packet_unref(&pkt);
            return 0;
        }else{
            m_aSeekTime = -1;
        }
    }

    //发送压缩数据到解码器
    int ret = avcodec_send_packet(m_aDecodeCtx,&pkt);

    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "avformat_find_stream_info error" << errbuf;
        return ret;
    }

    //释放pkt
    av_packet_unref(&pkt);

    //获取解码后的数据
    ret = avcodec_receive_frame(m_aDecodeCtx,m_aSwrInFrame);
    if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
        return 0;
    }else{
        if(ret < 0){
            char errbuf[1024];
            av_strerror(ret,errbuf,sizeof(errbuf));
            qDebug() << "avcodec_receive_frame error" << errbuf;
            return ret;
        }
    }

    //重采样输出的样本数
    int outSamples = av_rescale_rnd(m_aSwrOutSpec.nSampleRate,m_aSwrInFrame->nb_samples,m_aSwrInSpec.nSampleRate,AV_ROUND_UP);
    // 由于解码出来的PCM。跟SDL要求的PCM格式可能不一致，需要进行重采样
    ret = swr_convert(m_aSwrCtx,m_aSwrOutFrame->data,outSamples,(const uint8_t **)m_aSwrInFrame->data,m_aSwrInFrame->nb_samples);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "swr_convert error" << errbuf;
        return ret;
    }

    return ret * m_aSwrOutSpec.bytesPerSampleFrame;
}

int VideoPlayer::initSwr(){
    //重采样输入参数
    m_aSwrInSpec.sampleFmt = m_aDecodeCtx->sample_fmt;
    m_aSwrInSpec.nSampleRate = m_aDecodeCtx->sample_rate;
    m_aSwrInSpec.nChLayout = m_aDecodeCtx->channel_layout;
    m_aSwrInSpec.nCh = m_aDecodeCtx->channels;

    //重采样输出参数
    m_aSwrOutSpec.sampleFmt = AV_SAMPLE_FMT_S16;
    m_aSwrOutSpec.nSampleRate = 44100;
    m_aSwrOutSpec.nChLayout = AV_CH_LAYOUT_STEREO;
    m_aSwrOutSpec.nCh = av_get_channel_layout_nb_channels(m_aSwrOutSpec.nChLayout);
    m_aSwrOutSpec.bytesPerSampleFrame = m_aSwrOutSpec.nCh * av_get_bytes_per_sample(m_aSwrOutSpec.sampleFmt);

    //创建重采样上下文
    m_aSwrCtx = swr_alloc_set_opts(nullptr
                                   ,m_aSwrOutSpec.nChLayout
                                   ,m_aSwrOutSpec.sampleFmt
                                   ,m_aSwrOutSpec.nSampleRate
                                   ,m_aSwrInSpec.nChLayout
                                   ,m_aSwrInSpec.sampleFmt
                                   ,m_aSwrInSpec.nSampleRate
                                   ,0,nullptr);
    if(!m_aSwrCtx){
        qDebug() << "swr_alloc_set_opts error";
        return -1;
    }

    //初始化重采样上下文
    int ret = swr_init(m_aSwrCtx);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "swr_init error" << errbuf;
        return ret;
    }

    //初始化重采样的输入frame
    m_aSwrInFrame = av_frame_alloc();
    if(!m_aSwrInFrame){
        qDebug() << "av_frame_alloc error";
        return -1;
    }

    //初始化重采样的输出frame
    m_aSwrOutFrame = av_frame_alloc();
    if(!m_aSwrOutFrame){
        qDebug() << "av_frame_alloc eror";
        return -1;
    }
    //TODO 4096?
    //初始化重采样的输出frame的data[0]空间
    ret = av_samples_alloc(m_aSwrOutFrame->data,m_aSwrOutFrame->linesize
                           ,m_aSwrOutSpec.nCh,4096,m_aSwrOutSpec.sampleFmt,1);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "av_samples_alloc error" << errbuf;
        return ret;
    }

    return 0;
}
